%% Main Crazy Curl for MultiClass Classification %%%%%%%%%%%%%%%%%%%%%%%%%%
% 3/2013
% Marcelo Fiori, Guzman Hernandez, Alicia Fernandez and matias Di Martino.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Set General parameters, 
close all
clear all
clc

verbose = 2; %(1 - display text, 2 - display text and charts)
addpath ../toolboxs

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 1) Generate/Load Data %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if verbose>0, fprintf('Generating/Loading data ... \n'), end

% Define number of classes and dimensions
NumberOfClasses = 3;
NumberOfDimensions = 2;
MaxNumberOfSamplesPerClass = 2000;

[Samples,Labels] = GenerateData(NumberOfClasses,NumberOfDimensions, ...
                    MaxNumberOfSamplesPerClass);
NumberOfSamples = size(Samples,1);
Dimensions = size(Samples,2);
% define colors for different clases, 
aux = colormap(jet(NumberOfClasses));
clear Colors
for c = 1:NumberOfClasses,
    Colors{c} = aux(c,:);
end

if verbose>0, 
    for class = 1:NumberOfClasses, 
        fprintf('Samples of class %d : %d \n',class,sum(Labels==class))
    end
    fprintf('\n')
end

% Normalization ---------------------------------------
for dim = 1:NumberOfDimensions,
    Samples(:,dim) = (Samples(:,dim) - min(Samples(:,dim))) ...
           / ( max(Samples(:,dim)) - min(Samples(:,dim)) );  
end
% -----------------------------------------------------

% 
% /////////////////////////////////////////////////////////////////////////
% //// Display ////////////////////////////////////////////////////////////
% /////////////////////////////////////////////////////////////////////////
if verbose>1 && NumberOfDimensions < 4;% Display Data,
    
    % Open new figure
    h = figure('name','Data','NumberTitle','off');
       
    if NumberOfDimensions==2,
        for class = 1:NumberOfClasses,
            scatter(Samples(Labels==class,1),Samples(Labels==class,2),...
                'CData',Colors{class}); hold on,
        end
    else
        for class = 1:NumberOfClasses,
            scatter3(Samples(Labels==class,1),Samples(Labels==class,2),...
                Samples(Labels==class,3),'CData',Colors{class}); hold on,
        end
    end
    drawnow
end

% /////////////////////////////////////////////////////////////////////////

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 2) Split Data in train and test %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
TrainSamples = Samples([1:2:end],:);
TrainLabels = Labels([1:2:end]);
TestSamples = Samples([2:2:end],:);
TestLabels = Labels([2:2:end]);

if verbose>1 && NumberOfDimensions < 4;% Display Data,
    
    % Open new figure and display train samples
    h = figure('name','Training Samples','NumberTitle','off');       
    if NumberOfDimensions==2,
        for class = 1:NumberOfClasses,
            scatter(TrainSamples(TrainLabels==class,1),TrainSamples(TrainLabels==class,2),...
                'CData',Colors{class}); hold on,
        end
    else
        for class = 1:NumberOfClasses,
            scatter3(TrainSamples(TrainLabels==class,1),TrainSamples(TrainLabels==class,2),...
                     TrainSamples(TrainLabels==class,3),'CData',Colors{class}); hold on,
        end
    end
    
    % Open new figure and display test samples
    h = figure('name','Test Samples','NumberTitle','off');       
    if NumberOfDimensions==2,
        for class = 1:NumberOfClasses,
            scatter(TestSamples(TestLabels==class,1),TestSamples(TestLabels==class,2),...
                'CData',Colors{class}); hold on,
        end
    else
        for class = 1:NumberOfClasses,
            scatter3(TestSamples(TestLabels==class,1),TestSamples(TestLabels==class,2),...
                     TestSamples(TestLabels==class,3),'CData',Colors{class}); hold on,
        end
    end

end 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 3) Training Classifiers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if verbose>0, fprintf('Training Classifiers ... \n'), end

ClassifiersName = {'CC'};
NumberOfClassifiers = length(ClassifiersName);

for Class = 1:NumberOfClassifiers,
    switch ClassifiersName{Class},
        % /////////////////////////////////////////////////////////////////
        case 'CC', % //////////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
            parameters.verbose = 1; %{1 display some text, 2 also graphics}
            parameters.delta_t = 1e-1;
            parameters.tol = 0;
            parameters.max_iter = 200;
            parameters.GridSize = 200;
            parameters.Lambda0 = 0;
            parameters.Sigma = 0.04; % if Sigma = 0, the value is tuned 
                                     % automatically using 10 fold cv
            parameters.RegularityCoef = 0;
            [U,X] = CC_Train(TrainSamples,TrainLabels,parameters);
            
            % Save model, -----
            ClassifierModel{Class}.U = U;
            ClassifierModel{Class}.X = X;
            % -----------------
            
        % /////////////////////////////////////////////////////////////////
        case 'SVM', % /////////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
            verbose = 1; 
            Gamma = [0]; % if we use Gamma = 0; SVM_train use linear svm.
            Cost = [1e-2 200 10];
            SelectedMeasure = 'Gmean';
            [model] = SVM_train(TrainSamples,TrainLabels, [verbose], Gamma, Cost,SelectedMeasure);
            
            % Save model, -----
            ClassifierModel{Class} = model;
            % -----------------
        % /////////////////////////////////////////////////////////////////
        case 'SVM-RBF' % //////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
            verbose = 1; 
            Gamma = [.1 600 10]; Cost = [1e-1 1e3 10];
            SelectedMeasure = 'Gmean';
            [model] = SVM_train(TrainSamples,TrainLabels, [verbose], Gamma, Cost,SelectedMeasure);
            
            % Save model, -----
            ClassifierModel{Class} = model;
            % -----------------
        % /////////////////////////////////////////////////////////////////
        case 'linear' % ///////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////        
        %    w_linear = (labels*features')/(features*features');
        %    % Save model, -----
        %    ClassifierModel{Class}.w = w_linear;
        %    % -----------------
        % /////////////////////////////////////////////////////////////////
        case 'logistic'   % ///////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
        %   seed = 0*(labels*features')/(features*features');
        %    verbose = 1; tol = .01; maxIter = 150;
        %    w_logistic = logistic_regression(features',labels',verbose,tol,maxIter,seed');
        % 
        %    % normalize w,
        %    w_logistic = w_logistic/norm(w_logistic);
        %    
        %    % Save model, -----
        %    ClassifierModel{Class}.w = w_logistic;
        %    % -----------------
        % /////////////////////////////////////////////////////////////////    
        case 'adaboost' % /////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
        %    clear parameters,
        %    parameters.NumOfBoostingRounds = 400;
        %    parameters.verbose = 1;
        %    
        %    % Save model, -----
        %    ClassifierModel{Class} = TrainAdaboost (features,labels,parameters);       
        %    % -----------------
       otherwise error('Invalid Classifier name')
    end
end
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 4) Testing %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if verbose>0, fprintf('Testing ... \n'), end


for Class = 1:NumberOfClassifiers,
    switch ClassifiersName{Class},
        % /////////////////////////////////////////////////////////////////
        case 'CC', % //////////////////////////////////////////////////////
        % ///////////////////////////////////////////////////////////////// 
            U = ClassifierModel{Class}.U;
            X = ClassifierModel{Class}.X;
            clear parameters,
            parameters.verbose = 0;
            [TestPredictedLabels{Class}] = CC_Classify(TestSamples,U,X,parameters);
            [TrainPredictedLabels{Class}] = CC_Classify(TrainSamples,U,X,parameters);
            % -------------------------------------------------------------
        % /////////////////////////////////////////////////////////////////
        case 'SVM', % /////////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
            model = ClassifierModel{Class};
            [TestPredictedLabels{Class}, ~, ~] = svmpredict_libsvm(0*TestLabels, ...
                TestSamples, model);
            [TrainPredictedLabels{Class}, ~, ~] = svmpredict_libsvm(0*TrainLabels, ...
                TrainSamples, model);
        % /////////////////////////////////////////////////////////////////
        case 'SVM-RBF' % //////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
            model = ClassifierModel{Class};
            [TestPredictedLabels{Class}, ~, ~] = svmpredict_libsvm(0*TestLabels, ...
                TestSamples, model);
            [TrainPredictedLabels{Class}, ~, ~] = svmpredict_libsvm(0*TrainLabels, ...
                TrainSamples, model);
 
        
        % /////////////////////////////////////////////////////////////////
        case 'linear' % ///////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////        
        
        
        % /////////////////////////////////////////////////////////////////
        case 'logistic'   % ///////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
        
        
        % /////////////////////////////////////////////////////////////////    
        case 'adaboost' % /////////////////////////////////////////////////
        % /////////////////////////////////////////////////////////////////
        
        otherwise error('Invalid Classifier name')
    end
end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 4) Display Results %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for ClassifierIndex = 1:NumberOfClassifiers;
    Name = ClassifiersName{ClassifierIndex};
    TestPL = TestPredictedLabels{ClassifierIndex};
    [Gmean, Acc, AccClass] = Performance(TestLabels,TestPL);
    fprintf('////TEST////////////////////////////////////////////// \n')
    fprintf([Name '\n'])
    fprintf('\t Test Accuracy: %1.1f %% ',Acc*100)
    for c = 1:NumberOfClasses, fprintf(' || %1.1f ', AccClass(c)*100), end 
    fprintf('\n')
    fprintf('\t Test Gmean: %1.1f %% \n',Gmean*100)
    
    fprintf('////TRAIN////////////////////////////////////////////// \n')
    TrainPL = TrainPredictedLabels{ClassifierIndex};
    [Gmean, Acc,AccClass] = Performance(TrainLabels,TrainPL);
    fprintf([Name '\n'])
    fprintf('\t Test Accuracy: %1.1f %% ',Acc*100)
    for c = 1:NumberOfClasses, fprintf(' || %1.1f ', AccClass(c)*100), end 
    fprintf('\n')
    fprintf('\t Train Gmean: %1.1f %% \n',Gmean*100)
   
    if NumberOfDimensions == 2, 
        
        % Plot samples and labels, 
        figure('name',['Predicted Labels for ' Name]),
        for class = 1:NumberOfClasses,
            scatter(TestSamples(TestPL==class,1),TestSamples(TestPL==class,2), ...
                'CData',Colors{class}); hold on
        end
        
        % Plot errors, 
        figure('name',['Accuracy for ' Name]),
        scatter(TestSamples(TestPL==TestLabels,1),TestSamples(TestPL==TestLabels,2), ...
                'CData',[0 1 0]); hold on
        scatter(TestSamples(TestPL~=TestLabels & TestPL~=0,1),...
                TestSamples(TestPL~=TestLabels & TestPL~=0,2), ...
               'CData',[1 0 0]); hold on
        scatter(TestSamples(TestPL==0,1),...
                TestSamples(TestPL==0,2), ...
               'CData',[0 0 1]); hold on      
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


